Conversation
- Restrict GitHub toolsets from [default] (52 tools) to [pull_requests, repos] (only tools actually used) - Add pre-compute step to fetch PR diff before agent starts, reducing tool calls needed for initial PR analysis - Add max-turns: 15 to prevent runaway token consumption - Add explicit network: allowed: [github] to restrict egress - Update prompt to reference pre-fetched diff data Closes #1647 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
✅ Coverage Check PassedOverall Coverage
📁 Per-file Coverage Changes (1 files)
Coverage comparison generated by |
There was a problem hiding this comment.
Pull request overview
Updates the Security Guard agentic workflow configuration to reduce Claude token usage by narrowing the GitHub MCP tool surface area, limiting agent turns, and attempting to pre-inject PR diff context into the prompt.
Changes:
- Restrict GitHub MCP toolsets to
pull_requests+reposand add an enginemax-turnslimit. - Add a workflow step intended to pre-fetch PR changed-file patches and include them in the prompt.
- Re-compile the generated lock workflow with a newer
gh-awcompiler/action version.
Show a summary per file
| File | Description |
|---|---|
| .github/workflows/security-guard.md | Adjusts frontmatter (toolsets, max-turns, network) and adds a step + prompt section intended to inject pre-fetched PR diffs. |
| .github/workflows/security-guard.lock.yml | Re-generated compiled workflow reflecting the updated frontmatter and newer gh-aw tooling, including toolset restriction and max-turns. |
| .github/aw/actions-lock.json | Adds the pinned github/gh-aw-actions/setup@v0.65.5 entry used by the compiled workflow. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comments suppressed due to low confidence (4)
.github/workflows/security-guard.md:81
steps.pr-diff.outputs.PR_FILESis referenced in the prompt body, but thesteps:block runs as GitHub Actions steps and does not execute during prompt rendering unless it runs in the same job before the prompt is generated. With the current workflow compilation, the prompt is created in theactivationjob whilepr-diffruns later in theagentjob, so this placeholder will not be substituted with the diff.
Consider moving the PR-diff fetch into the activation job (pre-prompt) or switching to a mechanism that injects the diff into the prompt via activation outputs/artifacts.
## Changed Files (Pre-fetched)
The following PR diff has been pre-computed. Focus your security analysis on these changes:
${{ steps.pr-diff.outputs.PR_FILES }}
.github/workflows/security-guard.lock.yml:316
- This
pr-diffstep has the same output-capture issue as the.mdsource: thegh api ... | head -c 8000output is written to stdout rather than to$GITHUB_OUTPUT, soPR_FILESwill be empty.
Also, PR_NUMBER is sourced from github.event.pull_request.number without guarding for workflow_dispatch (where it will be empty), which will cause the gh api call to fail on manual runs. Consider adding an if: to run only when a PR number is present, or derive the PR number from inputs.
- env:
GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
id: pr-diff
name: Fetch PR changed files
run: "echo \"PR_FILES<<EOF\" >> $GITHUB_OUTPUT\ngh api \"repos/${GH_REPO}/pulls/${PR_NUMBER}/files\" \\\n --paginate --jq '.[] | \"### \\(.filename) (+\\(.additions)/-\\(.deletions))\\n\\(.patch // \"(binary)\")\\n\"' \\\n | head -c 8000\necho \"EOF\" >> $GITHUB_OUTPUT\n"
.github/workflows/security-guard.lock.yml:1067
- Same concern as earlier in the workflow: installing
@anthropic-ai/claude-code@latestin the detection job makes runs non-reproducible and can introduce unexpected breakages.
Pin to a specific version (or a controlled variable) for deterministic behavior.
sudo chmod +x /usr/local/bin/awf
- name: Install Claude Code CLI
run: npm install -g @anthropic-ai/claude-code@latest
- name: Execute Claude Code CLI
.github/workflows/security-guard.md:37
- This step will fail (or fetch the wrong URL) on
workflow_dispatchruns becausePR_NUMBERis set only fromgithub.event.pull_request.number, which is empty outside PR events. Add anif:guard so it only runs when a PR number exists, or accept a PR number as an explicit workflow_dispatch input and use that here.
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
GH_REPO: ${{ github.repository }}
- Files reviewed: 3/3 changed files
- Comments generated: 5
.github/workflows/security-guard.md
Outdated
| echo "PR_FILES<<EOF" >> $GITHUB_OUTPUT | ||
| gh api "repos/${GH_REPO}/pulls/${PR_NUMBER}/files" \ | ||
| --paginate --jq '.[] | "### \(.filename) (+\(.additions)/-\(.deletions))\n\(.patch // "(binary)")\n"' \ | ||
| | head -c 8000 | ||
| echo "EOF" >> $GITHUB_OUTPUT |
There was a problem hiding this comment.
The step output PR_FILES is not being populated: you write the PR_FILES<<EOF/EOF markers to $GITHUB_OUTPUT, but the gh api ... | head -c 8000 output is sent to stdout rather than appended to $GITHUB_OUTPUT. As a result, steps.pr-diff.outputs.PR_FILES will be empty.
Wrap the delimiter echoes and the gh api command in a single block that appends all lines to $GITHUB_OUTPUT (or redirect the gh api pipeline output into $GITHUB_OUTPUT between the markers).
This issue also appears in the following locations of the same file:
- line 35
- line 75
| echo "PR_FILES<<EOF" >> $GITHUB_OUTPUT | |
| gh api "repos/${GH_REPO}/pulls/${PR_NUMBER}/files" \ | |
| --paginate --jq '.[] | "### \(.filename) (+\(.additions)/-\(.deletions))\n\(.patch // "(binary)")\n"' \ | |
| | head -c 8000 | |
| echo "EOF" >> $GITHUB_OUTPUT | |
| { | |
| echo "PR_FILES<<EOF" | |
| gh api "repos/${GH_REPO}/pulls/${PR_NUMBER}/files" \ | |
| --paginate --jq '.[] | "### \(.filename) (+\(.additions)/-\(.deletions))\n\(.patch // "(binary)")\n"' \ | |
| | head -c 8000 | |
| echo "EOF" | |
| } >> "$GITHUB_OUTPUT" |
| toolsets: [pull_requests, repos] | ||
| network: | ||
| allowed: | ||
| - github |
There was a problem hiding this comment.
network.allowed is set to only github, but this workflow uses the Claude engine (and the generated lock file currently still allows many non-GitHub domains). If the intent is to truly restrict egress, please confirm which network groups are required for Claude/API-proxy operation and include them explicitly (e.g., the same baseline groups used by other Claude workflows), otherwise a future recompile could inadvertently block the model call path.
| - github | |
| - github | |
| - api-proxy |
| - name: Create prompt with built-in context | ||
| env: | ||
| GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt | ||
| GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} | ||
| GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl | ||
| GH_AW_EXPR_BAA3A6C6: ${{ steps.pr-diff.outputs.PR_FILES }} | ||
| GH_AW_GITHUB_ACTOR: ${{ github.actor }} | ||
| GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} |
There was a problem hiding this comment.
In the activation job, GH_AW_EXPR_BAA3A6C6 is set from ${{ steps.pr-diff.outputs.PR_FILES }}, but there is no pr-diff step in this job. This will evaluate to empty (or error depending on expression handling), so the prompt won’t receive the pre-fetched diff.
Add the Fetch PR changed files step to the activation job before prompt creation, or stop referencing steps.pr-diff from activation and source the content from an activation output/artifact instead.
This issue also appears on line 309 of the same file.
| activation: | ||
| if: (github.event_name != 'pull_request' || (github.event.pull_request.head.repo.id == github.repository_id && github.event.sender.type != 'Bot')) | ||
| if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.id == github.repository_id | ||
| runs-on: ubuntu-slim |
There was a problem hiding this comment.
The activation gate changed from excluding bot actors to allowing them (github.event.sender.type != 'Bot' was removed). This is a behavioral change not mentioned in the PR description and may increase workflow runs on automated PRs.
If this is intentional, please call it out in the PR description; otherwise, restore the bot exclusion to preserve prior behavior.
| sudo chmod +x /usr/local/bin/awf | ||
| - name: Install Claude Code CLI | ||
| run: npm install -g --silent @anthropic-ai/claude-code@2.1.47 | ||
| run: npm install -g @anthropic-ai/claude-code@latest |
There was a problem hiding this comment.
npm install -g @anthropic-ai/claude-code@latest makes the workflow non-deterministic and can break unexpectedly when a new Claude Code release is published.
Prefer pinning to a known-good version (or using a repo/org variable to control the version) so runs are reproducible.
This issue also appears on line 1064 of the same file.
| run: npm install -g @anthropic-ai/claude-code@latest | |
| env: | |
| CLAUDE_CODE_VERSION: ${{ vars.CLAUDE_CODE_VERSION }} | |
| run: | | |
| if [ -z "${CLAUDE_CODE_VERSION}" ]; then | |
| echo "CLAUDE_CODE_VERSION repo/org variable must be set to a known-good Claude Code CLI version" | |
| exit 1 | |
| fi | |
| npm install -g "@anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}" |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
- Fix GITHUB_OUTPUT redirect: wrap gh api + delimiters in block redirect so output actually reaches the step output variable - Add if: guard for workflow_dispatch where PR number is absent - Network groups: kept as github-only since compiler auto-adds Claude API domains; api-proxy is not a standard network group Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
The jq string interpolation with escaped quotes (\"") gets double-escaped by the gh-aw compiler's YAML quoting, producing invalid jq at runtime. Switch to string concatenation (+) which avoids nested quotes entirely. Also simplifies the binary fallback from '"(binary)"' to '""' since binary files with no patch data aren't useful for review. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The PR diff content can contain literal 'EOF' strings (e.g., from heredoc usage in shell scripts), which prematurely closes the GITHUB_OUTPUT delimiter. Use a timestamp-based unique delimiter (GHAW_PR_FILES_<epoch>) that won't collide with diff content. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
… delimiter error (#1651) When the PR diff exceeds 8000 bytes, `gh api ... | head -c 8000` causes SIGPIPE (exit 141) on the gh api process. GitHub Actions bash uses `-eo pipefail`, so the pipeline failure aborts the subshell before writing the closing heredoc delimiter to GITHUB_OUTPUT, resulting in: ##[error]Invalid value. Matching delimiter not found 'GHAW_PR_FILES_...' Fix: add `|| true` after `head -c 8000` to swallow the SIGPIPE/pipefail error, ensuring the closing delimiter is always written to GITHUB_OUTPUT. Fixes failing job: https://github.com/github/gh-aw-firewall/actions/runs/23964770751/job/69902358339 Agent-Logs-Url: https://github.com/github/gh-aw-firewall/sessions/c8b8f958-f52e-4390-af7d-f094e20e68da Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…ch (#1652) Agent-Logs-Url: https://github.com/github/gh-aw-firewall/sessions/0e4673e6-6f23-4e2d-8cc7-ccb922b81091 Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
head -c 8000 can truncate mid-line, leaving no trailing newline. The closing delimiter then appears on the same line as content and GitHub Actions fails to recognize it. Add an explicit echo to guarantee the delimiter is on its own line. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…ssions (#1653) Root cause: Claude exceeded max-turns (9 > 8) because mcp__playwright__browser_navigate failed 3 times with EACCES on /tmp/gh-aw/mcp-logs/playwright/*.yml, consuming extra turns. Fixes: 1. Add pre-step to create /tmp/gh-aw/mcp-logs/playwright with chmod 777 before MCP Gateway starts - this ensures the playwright container can write page snapshot YAML files 2. Increase max-turns from 8 to 12 to handle transient playwright retries more robustly Recompile smoke-claude.lock.yml and run post-processing scripts. Agent-Logs-Url: https://github.com/github/gh-aw-firewall/sessions/7c6a8e3c-9a33-488d-a2a7-d54bdaed44a2 Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Smoke Test Results✅ GitHub MCP: fix: increase smoke-claude max-turns and fix playwright log dir permissions (#1653), fix: recompile security-guard.lock.yml to fix frontmatter hash mismatch (#1652) Overall: PASS
|
🔥 Smoke Test Results
Overall: PASS PR by @lpcox, assignees: @lpcox,
|
|
Smoke test matrix (run 23965814007):
|
Smoke Test: GitHub Actions Services Connectivity
All checks passed.
|
🏗️ Build Test Suite Results
Overall: 8/8 ecosystems passed — ✅ PASS
|
Summary
Optimizes the security-guard workflow to reduce token consumption based on analysis from the token optimization advisor (#1647).
Changes
1. Restrict GitHub toolsets (Rec #1)
toolsets: [default]→toolsets: [pull_requests, repos]defaulttoolset loads 52 GitHub MCP tools; security-guard only uses ~7 (PR diff, file contents, search)pull_requests+reposprovide all needed tools while reducing tool schema overhead at the MCP gateway level2. Pre-compute PR diff (Rec #3)
steps:block that pre-fetches PR changed files viagh apibefore the agent starts${{ steps.pr-diff.outputs.PR_FILES }}get_pull_request_diff+get_pull_request_filestool calls (~2 round trips saved)3. Add max-turns limit (Rec #4)
max-turns: 15to prevent runaway token consumption4. Explicit network restriction
network: allowed: [github]to explicitly restrict egress to GitHub domains onlyExpected Impact
Based on token optimization advisor analysis:
Closes #1647